package com.ying.dogying.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ying.dogying.dao.ImPostDao;
import com.ying.dogying.entity.ImPost;
import com.ying.dogying.entity.dto.ImPostDto;
import com.ying.dogying.service.ImPostService;
import com.ying.dogying.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 李华明
 * @since 2020-06-01
 */
@Service
public class ImPostServiceImpl extends ServiceImpl<ImPostDao, ImPost> implements ImPostService {

    @Autowired
    private ImPostDao imPostDao;
    @Autowired
    private RedisUtils redisUtils;

    @Override
//    @Cacheable(cacheNames = "post:cache:", key = "'page:' + #page.current + '_' + #page.size + ', query:' + #categoryId")
    public IPage<ImPostDto> selectByParams(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {
        if (null == level) {
            level = -1;
        }

        QueryWrapper wrapper = new QueryWrapper<ImPost>()
                .eq(null != categoryId, "category_id", categoryId)
                .eq(null != userId, "user_id", userId)
                .eq(0 == level, "level", 0)
                .eq(0 < level, "level", level)
                .eq(null != recommend, "recommend", recommend)
                .orderByDesc(null != order, order);
        IPage<ImPostDto> pageData = imPostDao.selectByParams(page, wrapper);
        return pageData;
    }

    @Override
    public void initIndexWeekRank() {

        // 缓存最近7天的文章评论数量、不包括今天
        List<ImPost> posts = this.list(new QueryWrapper<ImPost>()
                .ge("create_time", DateUtil.offsetDay(new Date(), -7))
                .select("id, title, user_id, comment_count, view_count, create_time")
        );

        // 初始化文章的总评论数
        for (ImPost post : posts) {
            // 今天6.2，最近7天是5.26 —— 6.1
            String key = "post:rank:" + DateUtil.format(post.getCreateTime(), DatePattern.PURE_DATE_PATTERN);
            //缓存文章到set中，评论数量作为排行的标准
            redisUtils.zSet(key, post.getId(), post.getCommentCount());

            // 今天与创建时间相差多少天，如：今天6.2，创建时间6.1
            long between = DateUtil.between(new Date(), post.getCreateTime(), DateUnit.DAY);
            // 设置有效时间，如：7-1=6
            long expireTime = (7 - between) * 24 * 60 * 60;
            // 设置有效期，如：6天后自动过期
            redisUtils.expire(key, expireTime);
            // 缓存文章基本信息（hash结构：id、标题、评论数量、访问量）
            this.hashCachePostIdAndTitle(post, expireTime);
        }
        //7天阅读相加，做并集
        this.zUnionAndStoreLast7DaysForLastWeekRank();
    }

    @Override
    public ImPostDto selectOneByParams(Long id) {
        QueryWrapper wrapper = new QueryWrapper<ImPost>()
                .eq(null != id, "p.id", id);
        ImPostDto imPostDto = imPostDao.selectOneByParams(wrapper);
        return imPostDto;
    }

    @Override
    public void insertViewCount(ImPostDto imPostDto) {
        String key = "post:rank:" + imPostDto.getId();

        // 1、从缓存中获取viewCount
        Integer viewCount = (Integer) redisUtils.hget(key, "post:viewCount:");

        // 2、如果没有，就先从实体里面获取，再加一
        if(null != viewCount) {
            imPostDto.setViewCount(viewCount + 1);
        } else {
            imPostDto.setViewCount(imPostDto.getViewCount() + 1);
        }

        // 3、同步到缓存里面
        redisUtils.hset(key, "post:viewCount:", imPostDto.getViewCount());
    }

    @Override
    public List<ImPost> selectBy30Before(Long id) {
        Date date30Before = DateUtil.offsetDay(new Date(), -30).toJdkDate();
        List<ImPost> postList = imPostDao.selectList(new QueryWrapper<ImPost>()
                .eq("user_id", id)
                .ge("create_time", date30Before)
                .orderByDesc("create_time"));
        return postList;
    }

    @Override
    public IPage<ImPost> selectByUserId(Page page, Long profileId) {
        IPage myPublishedPost = imPostDao.selectPage(page, new QueryWrapper<ImPost>()
                .eq("user_id", profileId)
                .orderByDesc("create_time"));
        return myPublishedPost;
    }

    /**
     * hash结构缓存文章标题和id
     */
    private void hashCachePostIdAndTitle(ImPost post, long expireTime) {
        String key = "post:data:" + post.getId();
        boolean isExist = redisUtils.hasKey(key);
        if(!isExist) {
            //缓存文章基本信息（hash结构）
            redisUtils.hset(key, "post:id:", post.getId(), expireTime);
            redisUtils.hset(key, "post:title:", post.getTitle(), expireTime);
            redisUtils.hset(key, "post:commentCount:", post.getCommentCount(), expireTime);
            redisUtils.hset(key, "post:viewCount:", post.getViewCount(), expireTime);
        }
    }

    /**
     * 把最近7天的文章评论数量统计一下
     * 用于首页的7天评论排行榜
     */
    public void zUnionAndStoreLast7DaysForLastWeekRank() {
        // 当前时间的文章，如：6.2的文章
        String currentKey = "post:rank:" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        String destKey = "post:week:";

        List<String> otherKeys  = new ArrayList<>();
        // 当前时间 - 7 的文章，如：( 5.26、5.27、5.28、5.29、5.30、5.31、6.1 ) 6.2
        for(int i = -7 ; i < 0; i++) {
            String temp = "post:rank:" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_PATTERN);
            otherKeys.add(temp);
        }
        redisUtils.zUnionAndStore(currentKey, otherKeys, destKey);
    }
}
